// PongMainView.m
#import "PongMainView.h"

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <UIKit/UIHardware.h>
#import <UIKit/UIImage.h>
#import <UIKit/UIImageView.h>
#import <UIKit/UIView.h>
#import <UIKit/UIView-Hierarchy.h>
#import <UIKit/UIView-Rendering.h>
#import <UIKit/UIWindow.h>
#import <UIKit/UIView-Geometry.h>
#import "Common.h"
#import "GSEvent.h"
#import "PongGameView.h"
#import "PongFieldController.h"
#import "PongAudio.h"
#import "PongPrefs.h"
#import "PongPrefsView.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <objc/objc.h>
#include <objc/objc-runtime.h>

float offset = 50.0;
int pongAnim = 0;
extern CGRect thumbRect;

static NSString *prefFile = @"/var/root/Library/iPong";
PongPrefs *sharedPongPrefs;

/*
NOTE: This code comes from the ApolloIM project. Originally from NerveGas
on the #iphone-dev channel of osx86's IRC server.
*/

double objc_msgSend_fpret(id self, SEL op, ...) {
    Method method = class_getInstanceMethod(self->isa, op);
    int numArgs = method_getNumberOfArguments(method);
    
    if(numArgs == 2) {
        double (*imp)(id, SEL);
        imp = (double (*)(id, SEL))method->method_imp;
        return imp(self, op);
    } else if(numArgs == 3) {
        // FIXME: this code assumes the 3rd arg is 4 bytes
        va_list ap;
        va_start(ap, op);
        double (*imp)(id, SEL, void *);
        imp = (double (*)(id, SEL, void *))method->method_imp;
        return imp(self, op, va_arg(ap, void *));
    }
    
    // FIXME: need to work with multiple arguments/types
    fprintf(stderr, "ERROR: objc_msgSend_fpret, called on <%s %p> with selector %s, had to return 0.0\n", object_getClassName(self), self, sel_getName(op));
    return 0.0;
}


@interface PongMainView (PrivateAPI)

- (void)populatePreferences;
- (void)savePreferences;
- (void)prefsDidChange:(PongPrefs*)prefs;
- (void)makeACoolMoveTo:(id)target;

@end

@implementation PongMainView

- (void)alertSheet:(id)aSheet buttonClicked:(int)button;
{
	LogMethod();
	NSLog(@"Button = %i", button);
	switch (button) 
    {
        case 1:
			if (isServerErr)
			{
				NSLog(@"Try server again.");
				isServerErr = NO;
				break;
			}
			if (isClientErr)
			{
				NSLog(@"Try client again.");
				isClientErr = NO;
				break;
			}
            break;
        case 2:
			NSLog(@"Go back to prefs now.");
			[self makeACoolMoveTo:_prefsView];
			break;
        default:
            break;
    }
	[aSheet dismiss];
}
- (void)didDismissAlertSheet:(id)aSheet;
{
	LogMethod();
}

-(void)serverControllerDidBork:(NSException *)e
{
	inGameView = NO;	
	isServerErr = YES;
	
	UIAlertSheet * sheet = [[UIAlertSheet alloc] initWithFrame: CGRectMake(0, 240, 320, 240)];
	[sheet setDimsBackground:YES];
	[sheet setRunsModal:YES];
	[sheet setTitle:@"Network Server Error"];
	[sheet setBodyText:[NSString stringWithFormat:@"Debugging info: %@", [e reason]]];
	[sheet addButtonWithTitle:@"Try Again"];
	[sheet addButtonWithTitle:@"Cancel"];
	[sheet setDelegate: self];
	[sheet presentSheetFromAboveView: self];
}

-(void)clientControllerDidBork:(NSException *)e
{
	inGameView = NO;
	isClientErr = YES;
	
	UIAlertSheet * sheet = [[UIAlertSheet alloc] initWithFrame: CGRectMake(0, 240, 320, 240)];
	[sheet setTitle:@"Network Client Error"];
	[sheet setBodyText:[NSString stringWithFormat:@"Debugging info: %@", [e reason]]];
	[sheet addButtonWithTitle:@"Try Again"];
	[sheet addButtonWithTitle:@"Cancel"];
	[sheet setDelegate: self];
	[sheet presentSheetFromAboveView: self];
}

-(void)clientControllerIsConnecting
{
	LogMethod();
	[_prefsView startSpinning];
}

-(void)clientControllerFinishedConnecting
{
	LogMethod();
	[_prefsView stopSpinning];
}

- (void)heartbeatCallback:(NSTimer*)theTimer
{
	pongAnim += 1;
	if (inGameView)
	{
		[fieldController update];
		[_gameView setNeedsDisplay];
	}
	return;
}

- (id)initWithFrame:(struct CGRect)rect 
{	

	if ((self == [super initWithFrame: rect]) != nil) 
	{
        //LogMethod();
        srandom(time(NULL));
        animInterval = ANIM_INTERVAL;

		timer = [NSTimer scheduledTimerWithTimeInterval:animInterval target:self selector:@selector(heartbeatCallback:) userInfo:nil repeats:YES];
		[timer retain];
        
        [self populatePreferences];
        audio = [[PongAudio alloc] init];

		NSLog(@"StartView.m>>  Init startview...");
		
		NSLog(@"PongMainView.m>> Nav Bar...");
		
		_navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, offset)];
		[_navBar setBarStyle: 1];
		[_navBar setDelegate: self];
		[_navBar enableAnimation];

		// navtitle = [[UITextLabel alloc]initWithFrame:CGRectMake(10, 10, rect.size.width, 15.0f)];
		// [navtitle setText:@"iPong"];
		// [navtitle setCentersHorizontally:YES];
		// [_navBar addSubview:navtitle];

		NSLog(@"PongMainView.m>>  Initting base classes...");
		_gameView = [[PongGameView alloc] initWithFrame:rect];
		[_gameView setDelegate:self];
		_prefsView	= [[PongPrefsView alloc] initWithFrame:rect];
		[_prefsView	setDelegate:self];

		NSLog(@"PongMainView.m>>  Transition view...");
		_transitionView = [[UITransitionView alloc] initWithFrame: 
			CGRectMake(rect.origin.x, offset, rect.size.width, rect.size.height - offset)
		];

		NSLog(@"PongMainView.m>>  Starting navbar...");
		[self addSubview: _navBar];
		[self addSubview: _transitionView];
		[self makeACoolMoveTo:_prefsView];
		
    }
	return self;
}

- (void)dealloc
{
	LogMethod();
	[self savePreferences];
	
	[timer invalidate];
	[timer release]; timer = nil;
	[fieldController release]; fieldController = nil;
	[audio release]; audio = nil;
	
	[_navBar release]; _navBar = nil;
	[_transitionView release]; _transitionView = nil;
	// [navtitle release]; navtitle = nil;
	[_gameView release]; _gameView = nil;
	[_prefsView release]; _prefsView = nil;
	
	[sharedPongPrefs release]; sharedPongPrefs = nil;
	[super dealloc];
}

- (void)deviceOrientationChanged:(struct __GSEvent *)fp8;
{
	//LogMethod();
	int orient = [UIHardware deviceOrientation:YES];
	[fieldController setRotation:orient];
	[_gameView setRotationDegrees:(float)orient * 90.0f];
}

-(void)beginNewGame
{
	if (nil == fieldController)
	{
		CGRect rect = [self frame];
		// rect.size.height -= offset;
	    fieldController = [[PongFieldController alloc] initWithFieldRect:rect];
		[fieldController setDelegate:self];
	   	[_gameView setField:[fieldController field]];
	}
    [fieldController beginNewGame];
}

- (void)endGame
{
	[fieldController endGame];
}

-(void)gameDidEnd
{
    //LogMethod();
	if (inGameView)
	{
		LogMethod();
		[audio playLoser];
		//[self performSelector:@selector(beginNewGame) withObject:nil afterDelay:0.0];
		[self beginNewGame];
	}
}

-(void)bounce
{
	[audio playBounce];
}


- (void)populatePreferences
{
    //	NSLog(@"StartView>> Populating Accounts...");
	if (nil != sharedPongPrefs)
		[sharedPongPrefs release]; sharedPongPrefs = nil;
		
        if ([[NSFileManager defaultManager] fileExistsAtPath:prefFile]) 
        {
            // NSLog(@"loading prefs");
            sharedPongPrefs = [NSKeyedUnarchiver unarchiveObjectWithFile:prefFile];
            [sharedPongPrefs retain];
        } 
        else
        {
            // NSLog(@"Makin' new prefs");
            sharedPongPrefs = [[PongPrefs alloc] init];
            [self savePreferences];
        }
        if ((![sharedPongPrefs port] > 0)
            || (![[sharedPongPrefs hostName] length] > 0))
        {
            // NSLog(@"Makin' new prefs because those we loaded were sucky");
            sharedPongPrefs = [[PongPrefs alloc] init];
            [self savePreferences];
        }
        [sharedPongPrefs setDelegate:self];
}

-( void)savePreferences
{
	//LogMethod();
	// NSLog(@"savin' prefs (= %@)", sharedPongPrefs);
	[NSKeyedArchiver archiveRootObject:sharedPongPrefs toFile:prefFile];
}

-(void)prefsDidChange:(PongPrefs*)prefs
{
	[self savePreferences];
}

//thanks again to apolloim
- (void)makeACoolMoveTo:(id)target
{
	if (target == _gameView)
	{
		NSLog(@"Transitioning to main game view");
		inPrefsView = NO;
		inGameView = YES;
		//save the current state of the prefs view UI to the shared prefs object
		[_prefsView updatePrefs];
		[self savePreferences];
		[self beginNewGame];
		[_navBar showButtonsWithLeftTitle:@"Prefs" rightTitle:nil leftBack: YES];
		[_navBar removeFromSuperview];
		[_transitionView setFrame: [self frame]];
		[_gameView setFrame: [self frame]];
		[_transitionView transition:3 toView:_gameView];
	}
	if (target == _prefsView)
	{
		inPrefsView = YES;
		inGameView = NO;
		[self endGame];
		[_navBar removeFromSuperview];
		[self addSubview:_navBar];
		[_navBar showButtonsWithLeftTitle:nil rightTitle:@"Play game" leftBack: NO];
		NSLog(@"Trans: %@ to prefsView: %@", _transitionView, _prefsView);
		[_transitionView transition:3 toView:_prefsView];
	}
}

- (void)navigationBar:(UINavigationBar *)navbar buttonClicked:(int)button 
{
	if (inGameView)
	{
		[self makeACoolMoveTo: _prefsView];
	}
	else if (inPrefsView)
	{
		[self makeACoolMoveTo: _gameView];
	}
}

@end